import { useSysStore } from "../store";
import router from "../router";

// 是否在处理中
let processing = false;
// 离边框多远内算缩放
const dist = 10;
// 自动对齐时的单位
const unit = 8;
let currentCmp = {};

export const directives = {
    install(app) {
        // 按钮权限控制处理
        app.directive("perm", (el, binding) => {
            let funcCode = binding.value;
            if (!funcCode) {
                return;
            }

            const store = useSysStore();
            let show = true;
            if (!store.isSuperAdmin()) {
                let buttons = store.getButtons();
                let currentRoute = router.currentRoute.value;
                let path = currentRoute.meta.permPath || currentRoute.path;
                show = buttons.indexOf(path + ":" + funcCode) != -1;
            }

            if (!show) {
                el.style.display = "none";
            }
        });

        app.directive("drag", (el, binding) => {
            const cmp = binding.value.cmp;
            const setCurrent = binding.value.setCurrent;

            // 是否对齐
            let justify = binding.value.justify;

            // 移动位置或缩放的最小单位，避免元素缩放时与其它元素无法对齐
            const convertValue = (val) => {
                if (!justify) {
                    // 不用对齐方格时，进行无极缩放与拖动
                    return val;
                }
                return unit * Math.round(val / unit);
            };

            // 如果子元素有canvas元素， 则找到并进行处理
            const processCanvasChild = (children, callback) => {
                Array.from(children).forEach((child) => {
                    if (child.nodeName == "CANVAS") {
                        callback && callback(child);
                        return;
                    }

                    processCanvasChild(child.children, callback);
                });
            };

            // 解析类型，即缩放的方式或者移动，以及鼠标应当显示的样式
            const parseType = (x, y, ex, ey, width, height) => {
                let type = "m";
                let cursor = "default";

                // 简化版，暂只处理往下、往右及右下三种情况，也就是保持坐标不动，缩放宽高
                if (y + height - ey <= dist) {
                    if (x + width - ex <= dist) {
                        type = "rb";
                        cursor = "se-resize";
                    } else {
                        type = "b";
                        cursor = "s-resize";
                    }
                } else if (x + width - ex <= dist) {
                    type = "r";
                    cursor = "w-resize";
                }

                return {
                    type,
                    cursor,
                };
            };

            el.onmousemove = function (e) {
                if (processing) {
                    return;
                }

                // 鼠标移动到组件边缘时，显示不同鼠标样式
                let parent = el.parentNode;
                let parentLeft = parent.offsetLeft,
                    parentTop = parent.offsetTop;
                let width = el.offsetWidth,
                    height = el.offsetHeight;

                // 判断是放大缩小还是移动，如果是在对象边框的10px内，则为放大缩小，否则为移动
                // 相对于视窗的区域计算坐标
                let x = parentLeft + el.offsetLeft,
                    y = parentTop + el.offsetTop;
                let ex = e.clientX,
                    ey = e.clientY;

                // 处理类型
                let { type, cursor } = parseType(x, y, ex, ey, width, height);

                el.style.cursor = cursor;

                if (currentCmp.id != cmp.id) {
                    el.style.boxShadow = "0 0 5px #3e62d8";
                } else {
                    // el.style.border = "";
                    el.style.boxShadow = "";
                }

                // 子元素包含canvas时，需要找到canvas那层并设置其cursor
                processCanvasChild(el.children, (item) => (item.style.cursor = cursor));
            };

            el.onmouseleave = (e) => {
                if (processing) {
                    return;
                }

                // el.style.border = "";
                el.style.boxShadow = "";
                processCanvasChild(el.children, (item) => (item.style.cursor = "none"));
            };

            el.onmousedown = function (e) {
                if (e.button) {
                    // 只处理鼠标左键
                    return;
                }

                setCurrent && setCurrent(cmp);
                currentCmp = cmp;
                el.style.boxShadow = " 0 0 5px #3e62d8";

                e.preventDefault();

                // 保存原位置信息
                let oldLeft = el.offsetLeft;
                let oldTop = el.offsetTop;
                let parent = el.parentNode;
                let parentLeft = parent.offsetLeft,
                    parentTop = parent.offsetTop;

                let oldEX = e.clientX,
                    oldEY = e.clientY;

                // 鼠标按下，计算当前元素与父级元素的左上角距离
                // clientX/clientY:相对于视窗的位置，一般是浏览器的左上角
                // offsetLeft/offsetTop：相对于父元素的位置
                let disX = e.clientX - el.offsetLeft;
                let disY = e.clientY - el.offsetTop;
                let pWidth = parent.offsetWidth;
                let pHeight = parent.offsetHeight;
                let width = el.offsetWidth,
                    height = el.offsetHeight;

                // 判断是放大缩小还是移动，如果是在对象边框的10px内，则为放大缩小，否则为移动
                // 相对于视窗的区域计算坐标
                let x = parentLeft + el.offsetLeft,
                    y = parentTop + el.offsetTop;
                let ex = e.clientX,
                    ey = e.clientY;

                // 处理类型
                let { type, cursor } = parseType(x, y, ex, ey, width, height);

                el.style.cursor = cursor;
                processing = true;

                // 计算两边坐标
                document.onmousemove = function (e) {
                    e.preventDefault();

                    // 计算鼠标移动的距离
                    let mx = e.clientX - oldEX,
                        my = e.clientY - oldEY;

                    // 拖动过程中，不显示边框，但需要显示一个遮盖
                    el.style.border = "none";
                    el.style.opacity = "60%";
                    el.style.boxShadow = "0 0 5px #3e62d8";

                    switch (type) {
                        case "m": {
                            // 移动
                            // 计算落点X
                            let l = e.clientX - disX;
                            if (l <= 0) {
                                l = 0;
                            } else if (l >= pWidth - width) {
                                l = pWidth - width;
                            }

                            // 计算落点y
                            let t = e.clientY - disY;
                            if (t <= 0) {
                                t = 0;
                            // } else if (t >= pHeight - height) {
                            //     t = pHeight - height;
                            }

                            //移动当前元素
                            el.style.left = convertValue(l) + "px";
                            el.style.top = convertValue(t) + "px";
                            break;
                        }
                        case "rb":
                        case "b": {
                            // 底部缩放
                            let h = height + my;

                            // 不能超出父元素范围
                            if (h + oldTop > pHeight) {
                                h = pHeight - oldTop;
                            }

                            el.style.height = convertValue(h) + "px";
                            if (type == "b") {
                                break;
                            }
                        }
                        case "r": {
                            // 右侧缩放
                            let w = width + mx;
                            w = Math.min(w, pWidth - oldLeft);
                            el.style.width = convertValue(w) + "px";
                            break;
                        }
                    }
                };
                // 鼠标停止移动时，事件移除
                document.onmouseup = function () {
                    if (!processing) {
                        return;
                    }

                    el.style.border = "";
                    el.style.opacity = "";
                    el.style.boxShadow = "";
                    el.style.cursor = "default";

                    document.onmousemove = null;
                    document.onmouseup = null;
                    processing = false;

                    if (binding.value.callback) {
                        const format = (val) => 100 * val.toFixed(6) + "%";
                        const oldHeight = el.style.height;

                        // 如果原高度是px，则新的还得是px；否则使用百分比
                        let h, top;
                        if (oldHeight && oldHeight.endsWith("px")) {
                            h = el.offsetHeight + "px";
                            top = el.offsetTop + "px";
                        } else {
                            h = format(el.offsetHeight / pHeight);
                            top = format(el.offsetTop / pHeight);
                        }

                        // 计算位置、宽高，转换成比例
                        let w = format(el.offsetWidth / pWidth),
                            left = format(el.offsetLeft / pWidth);
                        binding.value.callback({ width: w, height: h, left, top });
                    }
                };
            };
        });
    },
};
